

#pragma once

#include <stddef.h>
#include "base/baseRefCounted.h"
#include "base/baseParamTraits.h"

namespace base
{
	namespace internal
	{

		// InvokerStorageBase is used to provide an opaque handle that the Callback
		// class can use to represent a function object with bound arguments.  It
		// behaves as an existential type that is used by a corresponding
		// DoInvoke function to perform the function execution.  This allows
		// us to shield the Callback class from the types of the bound argument via
		// "type erasure."
		class InvokerStorageBase : public RefCountedThreadSafe<InvokerStorageBase>
		{
		protected:
			friend class RefCountedThreadSafe<InvokerStorageBase>;
			virtual ~InvokerStorageBase() {}
		};

		// This structure exists purely to pass the returned |invoker_storage_| from
		// Bind() to Callback while avoiding an extra AddRef/Release() pair.
		//
		// To do this, the constructor of Callback<> must take a const-ref.  The
		// reference must be to a const object otherwise the compiler will emit a
		// warning about taking a reference to a temporary.
		//
		// Unfortunately, this means that the internal |invoker_storage_| field must
		// be made mutable.
		template<typename T>
		struct InvokerStorageHolder
		{
			explicit InvokerStorageHolder(T* invoker_storage)
				: invoker_storage_(invoker_storage) {}

			mutable scoped_refptr<InvokerStorageBase> invoker_storage_;
		};

		template<typename T>
		InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o)
		{
			return InvokerStorageHolder<T>(o);
		}

		// Holds the Callback methods that don't require specialization to reduce
		// template bloat.
		class CallbackBase
		{
		public:
			// Returns true if Callback is null (doesn't refer to anything).
			bool is_null() const;

			// Returns the Callback into an uninitalized state.
			void Reset();

		protected:
			bool Equals(const CallbackBase& other) const;

			// In C++, it is safe to cast function pointers to function pointers of
			// another type. It is not okay to use void*. We create a InvokeFuncStorage
			// that that can store our function pointer, and then cast it back to
			// the original type on usage.
			typedef void(*InvokeFuncStorage)(void);

			CallbackBase(InvokeFuncStorage polymorphic_invoke,
				scoped_refptr<InvokerStorageBase>* invoker_storage);

			// Force the destructor to be instaniated inside this translation unit so
			// that our subclasses will not get inlined versions.  Avoids more template
			// bloat.
			~CallbackBase();

			scoped_refptr<InvokerStorageBase> invoker_storage_;
			InvokeFuncStorage polymorphic_invoke_;
		};

	} //namespace internal

} //namespace base